﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.Windows.Forms;

namespace Liang.Net
{
    public delegate void ReceiveUDPDataHandler(object sender, ReceiveUDPDataArgs e);

    public class UDPClient
    {
        bool m_bQuit = false;
        UdpState m_udpState = new UdpState();

        void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                UdpState udpState = ar.AsyncState as UdpState;

                if (null != udpState)
                {
                    UdpClient u = udpState.udpClient;
                    IPEndPoint e = udpState.ipEndPoint;

                    if (!m_bQuit)
                    {
                        Byte[] receiveBytes = u.EndReceive(ar, ref e);

                        // 触发接收事件，将数据交给接收者处理
                        OnReceivedData(new ReceiveUDPDataArgs(receiveBytes, e.Address.ToString(), e.Port));

                        // 提交一个新的接收
                        u.BeginReceive(new AsyncCallback(ReceiveCallback), ar.AsyncState);
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("{0}", e.Message);
            }
        }

        /// <summary>
        /// 打开UDP通讯
        /// </summary>
        /// <param name="nPort"></param>
        /// <returns></returns>
        public bool Open(int nPort = 0)
        {
            m_bQuit = false;

            try
            {
                m_udpState.ipEndPoint = new IPEndPoint(IPAddress.Any, nPort);
                m_udpState.udpClient = new UdpClient(m_udpState.ipEndPoint);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
                return false;
            }

            try
            {
                m_udpState.udpClient.BeginReceive(new AsyncCallback(ReceiveCallback), m_udpState);
            }
            catch (ArgumentNullException e)
            {
                MessageBox.Show(e.Message);
                return false;
            }

            return true;
        }

        /// <summary>
        /// 关闭UDP连接
        /// <para>关闭后，若需要重新接收数据，则必须再次调用Open</para>
        /// </summary>
        public void Close()
        {
            m_bQuit = true;
            try
            {
                if (null != m_udpState.udpClient)
                {
                    m_udpState.udpClient.Close();
                }
            }
            catch (SocketException e)
            {
                MessageBox.Show(e.Message);
            }
        }

        public bool Send(string strMsg, string strIPAddr, int nPort)
        {
            Byte[] sendBytes = Encoding.ASCII.GetBytes(strMsg);
            return Send(sendBytes, strIPAddr, nPort);
        }

        public bool Send(byte[] buff, string strIPAddr, int nPort)
        {
            m_udpState.udpClient.EnableBroadcast = false;

            try
            {
                m_udpState.udpClient.Send(buff, buff.Length, strIPAddr, nPort);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return false;
            }

            return true;
        }

        /// <summary>
        /// 广播数据
        /// </summary>
        /// <param name="buff"></param>
        /// <param name="nPort"></param>
        /// <returns></returns>
        public bool Send(byte[] buff, int nPort)
        {
            try
            {
                m_udpState.udpClient.EnableBroadcast = true;
                m_udpState.udpClient.Send(buff, buff.Length, new IPEndPoint(IPAddress.Broadcast, nPort));
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }

            return true;
        }

        public event ReceiveUDPDataHandler ReceiveUDPDataEvent;

        void OnReceivedData(ReceiveUDPDataArgs e)
        {
            if (null != ReceiveUDPDataEvent)
            {
                ReceiveUDPDataEvent(this, e);
            }
        }
    }

    class UdpState
    {
        public UdpClient udpClient;
        public IPEndPoint ipEndPoint;
    }

    public class ReceiveUDPDataArgs
    {
        public readonly DataPackage dataPackage = new DataPackage();


        public ReceiveUDPDataArgs(byte[] data, string ip, int port)
        {
            dataPackage.ReceivedData = data.ToList<byte>();
            dataPackage.RemoteIP = ip;
            dataPackage.RemotePort = port;
        }
    }

    /// <summary>
    /// 数据包
    /// </summary>
    public class DataPackage
    {
        /// <summary>
        /// 收到的数据（字节）
        /// </summary>
        public List<byte> ReceivedData
        {
            get;
            set;
        }

        /// <summary>
        /// 发送方IP
        /// </summary>
        public string RemoteIP
        {
            get;
            set;
        }

        /// <summary>
        /// 发送方端口
        /// </summary>
        public int RemotePort
        {
            get;
            set;
        }
    }
}
